package ae.pcfc.etks.online.itworx.ehs.web.util;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;

import org.hibernate.Criteria;
import org.hibernate.EntityMode;
import org.hibernate.HibernateException;
import org.hibernate.criterion.CriteriaQuery;
import org.hibernate.criterion.Criterion;
import org.hibernate.engine.TypedValue;
import org.hibernate.type.CompositeType;
import org.hibernate.type.Type;
import org.hibernate.util.StringHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.interceptor.TransactionAspectSupport;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.servlet.support.RequestContext;

import ae.pcfc.etks.online.itworx.ehs.web.model.Rollback;



public class UtilCommon{
	
	private static Map<String, String> generalMap;
	
	private static ResourceBundleMessageSource messageSource;
	
	private static Logger log = LoggerFactory.getLogger(UtilCommon.class);

	public void setGeneralMap(Map<String, String> generalMap) {
		UtilCommon.generalMap = generalMap;
	}
	
	public void setMessageSource(
			ResourceBundleMessageSource messageSource) {
		UtilCommon.messageSource = messageSource;
	}




	public static Date getDateFromString(String date) {
		try {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			return df.parse(date);
		} catch (ParseException ex) {
			return null;
		}
	}
	
	public static Date getFormattedDate(Date dat){
		try{
			SimpleDateFormat smp = new SimpleDateFormat("dd/MM/yyyy");
			String formatedDateString = smp.format(dat);
			Date formattedDateDate = smp.parse(formatedDateString);
			return formattedDateDate;
		}catch(ParseException ex){
			log.error("UtilCommon.getFormattedDate Date not parsable ",ex);
			return null;
		}
	}
	
	public static String getStringFromDate(Date date) {
		try {
			SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
			String formattedDate = df.format(date);
			return formattedDate;
		} catch (Exception e) {
			return "";
		}

	}

	public static String getDDMMYYYFromDate(Date date) {
		try {
			SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy");
			String formattedDate = df.format(date);
			return formattedDate;
		} catch (Exception e) {
			return "";
		}

	}
	
	public static String getCurrentDateAsDDMMYYYY() {

		Date date = new Date();
		// Keep the MM upper case
		SimpleDateFormat df = new SimpleDateFormat("dd/MM/yyyy");
		String formattedDate = df.format(date);
		return formattedDate;

	}

	public static boolean dateCompare(Date firstDate, Date secondDate) {

		try {
			if (secondDate.compareTo(firstDate) == 0) {
				return true;
			} else
				return false;

		} catch (Exception e) {
			return false;
		}
	}
	
	public static String toString(Object obj){
		return (obj == null) ? null : obj.toString();
	}
	
	public static Date getCurrentDate(){
		return new java.sql.Date(new Date().getTime());
	}

	public static boolean isEmpty(String str) {
		return (str==null || "".equals(str.trim()));
	}

	public static String trim(String str) {
		return (str==null)?null:str.trim();
	}
	
	public static void sort(Collection<?> collection, String field, boolean sortAsc) {
		Collections.sort((List<?>) collection, new DynamicComparator(field,
				sortAsc));
	}

	public static void sort(Collection<?> collection, String field,
			boolean sortAsc, boolean stringAsNumber) {
		Collections.sort((List<?>) collection, new DynamicComparator(field,
				sortAsc, stringAsNumber));
	}

	public static void sort(Object[] objects, boolean sortAsc) {
		Arrays.sort(objects, new DynamicComparator(sortAsc));
	}

	public static <T> void sort(T[] objects, boolean sortAsc,
			final boolean stringAsNumber) {
		Arrays.sort(objects, new DynamicComparator(sortAsc, stringAsNumber));
	}
	
	public static <T> List<T> getCollectionPage(List<T> collection, int pageIndex,int pageSize){
		if(collection == null || collection.size() == 0 || collection.size() <= pageSize)
			return collection;
		List<T> pagedCollection = null;
		long collectionSize = collection.size();
		int pageLength = Integer.parseInt(UtilCommon.generalMap.get("pageSize"));
		int startIdx = pageLength*(pageIndex-1);
		int dueTo = pageLength*pageIndex;
		int endIdx = (dueTo>collectionSize)? (int)collectionSize : dueTo;
		pagedCollection = new ArrayList<T>();
		for(int i=startIdx;i<endIdx;i++){
			pagedCollection.add(collection.get(i));
		}
		return pagedCollection;
	} 
	
	public static int getCollectionPagesCount(Collection<?> collection,int pageSize){
		if(collection == null || collection.size() == 0 || collection.size() <= pageSize)
			return 1;
		else if(collection.size()%pageSize == 0)
			return collection.size()/pageSize;
		else
			return (collection.size()/pageSize)+1;
		
	}
	
    /**
     * Gets the current user's id from the Spring request context
     * @return current user's userId
     */
    public static String getLoggedInUserName() {
    	ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    	if(requestAttributes != null 
    			&& requestAttributes.getRequest() != null 
    			&& requestAttributes.getRequest().getUserPrincipal() != null){
    		return requestAttributes.getRequest().getUserPrincipal().getName();
    	} else {
    		return "anonymous";
    	}
    }
    
    public static String getLoggedInUserName(HttpServletRequest request) {
   		return request.getUserPrincipal().getName();
    }
    
    public static UserDetails getLoggedInUserDetails(){
        SecurityContext securityContext = SecurityContextHolder.getContext();
        Authentication authentication = securityContext.getAuthentication();
        if (authentication != null) {
            Object principal = authentication.getPrincipal();
            return principal instanceof UserDetails ? (UserDetails) principal : null;
        }
        return null;
    }

    
    public static String getContextPath(){
    	ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    	String contextPath = null;
    	if(requestAttributes != null){
    		HttpServletRequest request = requestAttributes.getRequest();
   	  		ServletContext context = request.getSession().getServletContext();
   	  		contextPath = context.getContextPath();
    	} else {
    		contextPath = getGeneralMapValue("contextPath");
    	}
    	return contextPath;
    }
    
	public static String getResourceMessage(String key,Object[] args, Locale locale){
    	ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
    	String message = null;
    	if(requestAttributes != null){
	    	HttpServletRequest request = requestAttributes.getRequest();
		    RequestContext ctx = new RequestContext(request);
		    message = ctx.getMessageSource().getMessage(key, args, locale);
    	} else {
    		message = messageSource.getMessage(key, args, locale);
    	}
    	return message;
	}
	
	public static Rollback preppareIMSRollback(String imsLogId){
		Rollback rb = new Rollback();
		rb.setImsLogId(imsLogId);
		return rb;
	}
	
	public static Rollback preppareFNPRollback(String fnpMessage, String fnpPaymentAdviceNumber, String fnpTransactionNumber, String fnpUserName){
		Rollback rb = new Rollback();
		rb.setFnpMessage(fnpMessage);
		rb.setFnpPaymentAdviceNumber(fnpPaymentAdviceNumber);
		rb.setFnpTransactionNumber(fnpTransactionNumber);
		rb.setFnpUserName(fnpUserName);
		return rb;
	}
	
	public static Rollback prepareRollback(String fnpMessage, String fnpPaymentAdviceNumber, String fnpTransactionNumber, String fnpUserName, String imsLogId){
		Rollback rb = new Rollback();
		rb.setFnpMessage(fnpMessage);
		rb.setFnpPaymentAdviceNumber(fnpPaymentAdviceNumber);
		rb.setFnpTransactionNumber(fnpTransactionNumber);
		rb.setFnpUserName(fnpUserName);
		rb.setImsLogId(imsLogId);
		return rb;
	}
	
	public static String underscore(String str){
		return (str == null)?null:str.replaceAll(" ", "_");
	}
	
	public static String getGeneralMapValue(String key){
		return UtilCommon.generalMap.get(key);
	}
	
	public static Integer getGeneralMapAsInteger(String key){
		Integer value = null;
		String strValue = UtilCommon.generalMap.get(key);
		if(strValue == null)
			return null;
		try {
			value = Integer.parseInt(strValue);
		} catch (NumberFormatException  e) {
			log.error("UtilCommon.getGeneralMapAsInteger() - value ["+strValue+"] not parse",e);
		}
		return value;
	}
	
	public static Criterion insensitiveIn(final String propertyName, final String[] values) {
		return new Criterion() {
			@Override
			public String toSqlString(Criteria criteria,
					CriteriaQuery criteriaQuery) throws HibernateException {
				 String[] columns = criteriaQuery.findColumns(propertyName, criteria);
				 for(int i = 0;i<columns.length;i++){
					 columns[i] = "lower("+columns[i]+")";
				 }
				 if ( criteriaQuery.getFactory().getDialect().supportsRowValueConstructorSyntaxInInList() || columns.length<=1) {
		            String singleValueParam = StringHelper.repeat( "?, ",columns.length - 1 ) + "?";
		            if ( columns.length > 1 )
		                singleValueParam = '(' + singleValueParam + ')';
		            String params = values.length > 0 ? StringHelper.repeat(singleValueParam + ", ", values.length - 1 ) + singleValueParam : "";
		            String cols = StringHelper.join( ", ", columns );
		            if ( columns.length > 1 )
		                cols = '(' + cols + ')';
		            return cols + " in (" + params + ')';
		        } else {
		           String cols = " ( " + StringHelper.join( " = ? and ", columns ) + "= ? ) ";
		             cols = values.length > 0 ? StringHelper.repeat( cols
		                    + "or ", values.length - 1 )
		                    + cols : "";
		            cols = " ( " + cols + " ) ";
		            return cols;
		        }
			}

			@Override
			public TypedValue[] getTypedValues(Criteria criteria,
					CriteriaQuery criteriaQuery) throws HibernateException {
				ArrayList list = new ArrayList();
				Type type = criteriaQuery.getTypeUsingProjection(criteria, propertyName);
				if ( type.isComponentType() ) {
					CompositeType actype = (CompositeType) type;
					Type[] types = actype.getSubtypes();
					for ( int j=0; j<values.length; j++ ) {
						for ( int i=0; i<types.length; i++ ) {
							Object subval = values[j]==null ? 
								null : 
								actype.getPropertyValues( values[j].toLowerCase(), EntityMode.POJO )[i];
							list.add( new TypedValue( types[i], subval, EntityMode.POJO ) );
						}
					}
				}
				else {
					for ( int j=0; j<values.length; j++ ) {
						list.add( new TypedValue( type, values[j].toLowerCase(), EntityMode.POJO ) );
					}
				}
				return (TypedValue[]) list.toArray( new TypedValue[ list.size() ] );
			}
			
			@Override
			public String toString() {
				return propertyName + " in (" + StringHelper.toString(values) + ')';
			}
		};
	}
	
	public static String getFormmattedRequestId(String serviceName, String requestType, long requestId, Date creationDate){
		if(ServiceValidator.validateString(serviceName) && ServiceValidator.validateString(requestType) && requestId > 0 && ServiceValidator.validateString(creationDate.toString())){
			return serviceName + "_" + requestType + "_" + getStringFromDate(creationDate) + "_" + requestId;
		}
		return "";
	}
	
	public static boolean isInteger(String str){
		try{
			Integer.parseInt(str);
			return true;
		}catch (NumberFormatException e) {
			return false;
		}
	}
	
	public static void rollbackTransaction(){
		try{
			TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
		} catch(NoTransactionException e){
		} catch (Exception e) {
			log.error("UtilCommon.rollbackTransaction() - failed to rollback transaction ",e);
		}
	}
	
	public static String generateFNPTransactioNum(String staticTXNPart)
	{
		SimpleDateFormat formatter=new SimpleDateFormat("yyyyMMddHHmmssSSS");
		Date currentDate=new Date();
		
		String txnNumber=staticTXNPart+"-"+formatter.format(currentDate);
		
		return txnNumber;
	}
	
}